#!/usr/bin/perl
##########################################################################################################
## Author: Kjell R. Kjørstad                                                                            ##
## E-mail: kjell@kolug.org - for questions or comments.          					##
## File: This is the bot itself, this is the file to start when you want it online.                     ##
## Purpose: Simple IRC Bot created to guard your channel, this is a skeleton, ready for new functions.  ##
##	    The whole access system is database driven.							##
##													##
##           												##
## NOTE: If you do changes to existing code in any way, or have other comments an e-mail would be       ##
##	 highly appreciated.          	                        					##
##													##
## License:												##
##       This file is part of chanKeeper.								##
##													##
##       chanKeeper is free software: you can redistribute it and/or modify				##
##       it under the terms of the GNU General Public License as published by				##
##       the Free Software Foundation, either version 3 of the License, or				##
##       (at your option) any later version.								##
##													##
##       chanKeeper is distributed in the hope that it will be useful,					##
##       but WITHOUT ANY WARRANTY; without even the implied warranty of					##
##       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the					##
##       GNU General Public License for more details.							##
##   													##
##       You should have received a copy of the GNU General Public License				##
##       along with chanKeeper.  If not, see <http://www.gnu.org/licenses/>.				##
## 													##
## Copyright: Copyright © 2009, Kjell R. Kjørstad							##
##                                                                                                      ##
##########################################################################################################

######################################
#### Modules which will be loaded ####
######################################


use warnings;
use strict;
use POE qw( Component::IRC Component::IRC::Plugin::CTCP Component::IRC::Plugin::CycleEmpty Component::IRC::State Component::IRC::Plugin::Logger Component::SSLify Component::IRC::Plugin::Connector );
use DBI;
use Digest::MD5;
use searchlogs;
use ircuac;
require "conf/bot.conf";
our ($botnick, $botserver, $botport, $ssl, $chan, $cmode, $logdir, $enable_private_log, $enable_public_log, $logsort, $botmaster, $output, $useless_greetings, $minpasslength, $debug, $diemsg, $botusername, $comchar );

###################################
#### Subroutine for  help text ####
###################################

#The helptext itself, used in both on_msg and on_public
sub helpt() {

my ($helptext) =   ("      This bot will provide basic access control to your IRC Channel. It's a skeleton which is easy to upgrade,
				  enjoy! - Remember to add command character when initiating commands, if commandchar is ! then help
				  would be !help. Your command character is: \"$comchar\"
	     
	     PUBLIC AND PRIVATE COMMANDS:
	     help		 = Send you this help text. [ALL]	    
	     op <nickname> 	 = Op yourself or <nickname> in $chan. [200]	     
	     deop <nickname> 	 = Deop yourself or <nickname> in $chan. [200]	     
	     voice (<nickname>) = Voice yourself or <nickname> in $chan. [100]
	     admins 		 = Lists admins (All users with an access level of 500 or greater). [ALL]
	     topic <TOPIC> 	 = Set topic in $chan to <TOPIC>. [50]
	     md5 <message> 	 = Return the md5hash of your <message>. [ALL] - FOR PASSWORDS: PLEASE use this in private message with $botnick only.
	     unident 		 = Unidentify with the bot. [ALL]
	     
	     The three last ones is possible to run in $chan, but you shall NOT DO IT!
	     If these commands are initiated in $chan, the account will automatically be suspended.
 
	     register <username> <password> = Register you with the bot, with <username> and <password>. You need an admin to approve you and grant you access. [ALL] 
	     ident <username> <password>    = Identifies you with the bot. [ALL] 
	     setpass <old password> <new password> = Change password from old to new. [ALL]

	     END OF $botnick HELP");

return($helptext);
}

sub adminhelp() {

my ($adminhelp) = (" 	   As an administrator, with an accesslevel of 500 or more you have some special rights,
	    these rights are in addition to the ones in !help. The required accesslevel is stated at the end of the help line in [], for example [500].
      
	    PUBLIC AND PRIVATE COMMANDS:
	    adduser <username> <accesslevel> 		= Add <username> with <accesslevel>. [500]
	    deluser <username>              	        = Delete <username>. [500]
	    suspend <username> <reason>     	        = Suspend user with reason. [500]
	    unsuspend <username> <reason>   	        = Unsuspend user with reason. [500]
	    listsuspend 		       		= Lists all users which are suspended, with reason. [500]
	    listapprovals		       		= Lists all users which are waiting for approval. [500]
	    approve <username> <access level> 		= Approve <username> registration, and giving <accesslevel>. [500]
	    die 					= Bot quit. [1000]
	    
	    END OF $botnick ADMINHELP");

return($adminhelp);
}

#### Code start ####


#######################################
#### START: Section for BOT-object ####
#######################################

#Subroutine for channel.
sub CHANNEL () { "$chan" }

#Create the component that will represent an IRC network.
my ($irc) = POE::Component::IRC::State->spawn();

#Create the bot session.  The new() call specifies the events the bot
#knows about and the functions that will handle those events.
POE::Session->create(
    inline_states => {
        _start     => \&bot_start,
        irc_001    => \&on_connect,
	irc_join => \&on_join,
	irc_user_mode => \&on_mode,
	irc_invite	=> \&on_invite,
	irc_mode	=> \&on_mode,
	irc_quit	=> \&on_quit,
	irc_msg		=> \&on_privandpub,
	irc_public	=> \&on_privandpub,
	irc_disconnected => \&on_disconnect,
    },
);

# Run the bot until it is done.
$poe_kernel->run();

#The bot session has started.  Register this bot with the "magnet"
#IRC component.  Select a nickname.  Connect to a server.
sub bot_start {
    my ($kernel, $heap) = @_[KERNEL ,HEAP];
    
    #If channel is empty and the bot is not oped it will rejoin to get oped.
    $irc->plugin_add('CycleEmpty', POE::Component::IRC::Plugin::CycleEmpty->new());

    #Create and load a CTCP plugin, unnecessary really, but why not?
    $irc->plugin_add( 'CTCP' => POE::Component::IRC::Plugin::CTCP->new(
	    #Version reply, should NOT be changed, if no changes are made to the BOT.
	    version => "chanKeeper - BOT written in Perl by Kjell R. Kjørstad <kjell\@kolug.org>",
    ));

    $irc->plugin_add('Logger', POE::Component::IRC::Plugin::Logger->new(
	    Path    => "$logdir",
	    Private => "$enable_private_log",
	    Public  => "$enable_public_log",
	    Sort_by_date => "$logsort",
    ));

    $heap->{connector} = POE::Component::IRC::Plugin::Connector->new();
    $irc->plugin_add( 'Connector' => $heap->{connector} );

    #Decides which events to listen for, all is a pretty good solution as you can throw away what you don't need.
    $irc->yield( register => "all" );

    my $nick = "$botnick";
    $irc->yield( connect =>
          { Nick => $nick,
            Username => "$botusername",
            Ircname  => 'chanKeeper BOT written in Perl',
            Server   => "$botserver",
            Port     => "$botport",
	    UseSSL   => "$ssl",  
	    Debug => '$debug',
          }
    );
    
    $kernel->delay( 'lag_o_meter' => 60 );
    return;
}

sub lag_o_meter {
     my ($kernel,$heap) = @_[KERNEL,HEAP];
     print 'Time: ' . time() . ' Lag: ' . $heap->{connector}->lag() . "\n";
     $kernel->delay( 'lag_o_meter' => 60 );
     return;
}

# The bot has successfully connected to a server.  Join a channel.
sub on_connect {
    $irc->yield( join => CHANNEL );
}


#### SECTION END ####

############################
#### Custom subroutines ####
############################

#Subroutine which use the irc->yield.
sub text2irc {
    $irc->yield( privmsg => $_[0], "$_[1]\n");
}

#Sub to log commands.
sub logcommands {
    my $ts = scalar localtime;
    my $commandlog = "$logdir/" . "commandlog.txt";
    open(LOG, ">>$commandlog");
    print LOG "[$ts]: @_\n";
    close(LOG);
}

#Subroutine for hashing whatever sent into it, routine will return the hash.
sub md5hash {
    my $md5 = Digest::MD5->new;
    $md5->add($_[0]);
    my $md5hash = $md5->hexdigest;
    return $md5hash;
}


##########################################
#### Subroutine for on_join(irc_join) ####
##########################################
sub on_join {
    my ( $who, $channel ) = @_[ ARG0, ARG1 ];
    my $nick = ( split /!/, $who)[0];
    my $help = "$comchar"."help";
    #Will set channel mode to $cmode when bot joins channel, if mode is not already set.
    $irc->yield( mode => CHANNEL, $cmode );	
    if ( $useless_greetings == '1' and $nick ne $botnick ) {
	text2irc($chan,"Welcome to $channel $nick, please see my $help for help.");
    }
}

#### SECTION END ####

############################################
#### Subroutine for on_private(irc_msg) ####
############################################

#The bot has recieved a private message. Parse it for commands, and respond to interesting things.
sub on_private {
    my ( $kern, $who, $where, $msg ) = @_[ KERNEL, ARG0, ARG1, ARG2 ];
    my $name = (split /!/, $who )[0];
    my $wherefrom = $where->[0];
    if ( $output == '1' ) {
	#Spam channel messages to shell. 
	my $ts = scalar localtime;
	print " [$ts] <$who:$wherefrom> $msg\n";
    }

    ##############################################################
    #### ircuac (IRC User and Access Control) functions start ####
    ##############################################################



    ##############################################################
    #### ircuac (IRC User and Access Control) functions stop  ####
    ##############################################################

    #Sends annonymous message to channel from bot.
    if ( $msg =~ /^!ashout (.+)/iog ) {
	$msg =~ s/!ashout//io;
	my @message = (split / /, $msg );
	$irc->yield( privmsg => CHANNEL, @message );
    }
}

#### SECTION END ####

##############################################################################
#### Subroutine for on_private(irc_msg) and on_public(irc_public) 	  ####
#### Commands you would like to work for priv AND pub can be placed here. ####      
##############################################################################

sub on_privandpub {
    my ( $kern, $who, $where, $msg ) = @_[ KERNEL, ARG0, ARG1, ARG2 ];
    my $name = (split /!/, $who )[0];
    my $wherefrom = $where->[0];
    if ( $output == '1' ) {
	#Spam channel messages to shell. 
	my $ts = scalar localtime;
	print " [$ts] <$who:$wherefrom> $msg\n";
    }

    #Commands available, adding them here to be able to add command character to config.
    my $adduser = "$comchar"."adduser";
    my $deluser = "$comchar"."deluser";
    my $listapprovals = "$comchar"."listapprovals";
    my $approve = "$comchar"."approve";
    my $listsuspend = "$comchar"."listsuspend";
    my $suspend = "$comchar"."suspend";
    my $unsuspend = "$comchar"."unsuspend";
    my $unident = "$comchar"."unident";
    my $admins = "$comchar"."admins";
    my $register = "$comchar"."register";
    my $setpass = "$comchar"."setpass";
    my $ident = "$comchar"."ident";
    my $leavemsg = "$comchar"."leavemsg";
    my $listmsg = "$comchar"."listmsg";
    my $readmsg = "$comchar"."readmsg";
    my $delmsg = "$comchar"."delmsg";
    my $logsearch = "$comchar"."logsearch";
    my $replay = "$comchar"."replay";
    my $shout = "$comchar"."shout";
    my $ashout = "$comchar"."ashout";
    my $topic = "$comchar"."topic";
    my $md5msg = "$comchar"."md5";
    my $op = "$comchar"."op";
    my $deop = "$comchar"."deop";
    my $voice = "$comchar"."voice";
    my $invitemsg = "$comchar"."invite";
    my $die = "$comchar"."die";
    my $helpt = "$comchar"."help";
    my $admhlp = "$comchar"."\@help";
    
    #Help text, responds to !help on private msg.
    if ( my ($help) = $msg =~ /^$helpt$/ ) {
	#Splitting up helptext for spamming to user who initiate help.
	my @help = (split /\n/, helpt() );
	
	#Printing to user.
	foreach my $line ( @help ) {
	    #$irc->yield( privmsg => $name, $line );    
	    text2irc($name, $line);
	}
    }

    #ADMIN-Help text, responds to @help on private msg or in chan.
    if ( $msg =~ /^$admhlp$/ and ircuac->accesscheck($name,$who) >= '500' ) {
	#Splitting up helptext for spamming to user who initiate help.
	my @help = (split /\n/, adminhelp() );
	
	#Printing to user.
	foreach my $line ( @help ) {
	    #$irc->yield( privmsg => $name, $line );    
	    text2irc($name, $line);
	}
    } elsif ($msg =~ /^$admhlp$/ and ircuac->accesscheck($name,$who) < '500') {
	text2irc($name,"You do not have access to get the adminhelp, you need 500 or more.");
    }
        
    ##############################################################
    #### ircuac (IRC User and Access Control) functions start ####
    ##############################################################


    ##########################
    #### Add user to bot. ####
    ##########################   
    if ( $msg =~ m/^$adduser (.+)/ and ircuac->accesscheck($name,$who) >= '500' ) {
	$msg =~ s/$adduser//;
	my @userinfo = ( split / /, $msg );
	#Defining user, host and access, just so I don't have to remember the array from time to time. Easier if changes are made and so on. Not neccessary, but nice.
	my $user = $userinfo[1];
	my $access = $userinfo[2];
	my $senduser2sub = ircuac->adduser($user, $access);
	
	if ( $senduser2sub == '1') {
	    text2irc($name, "$user added to system.");
	}

	if ( $senduser2sub == '0') {
	    text2irc($name, "$user already exist in system.");
	} 
    } elsif ( $msg =~ m/^$adduser (.+)/ and ircuac->accesscheck($name,$who) < '500' ) {
	text2irc($name, "You're not allowed to add users.");
    }
	
    
    
    ###############################
    #### Delete user from bot. ####
    ###############################
    if ( $msg =~ m/^$deluser (.+)/ and ircuac->accesscheck($name,$who) >= '500' ) {
	$msg =~ s/$deluser //;
	chomp($msg);
	my $send2sub = ircuac->deluser($msg);
	
	if ( $send2sub == '1' ) {
	    text2irc($name,"$msg deleted from system.");
	} 
      
	if ( $send2sub == '0' )	{   
	    text2irc($name,"$msg does not exist.");
	}
    } elsif ( $msg =~ m/^$deluser (.+)/ and ircuac->accesscheck($name,$who) < '500' ) {
	text2irc($name,"You do not have the appropriate access to delete users.");
    }

    ##########################################
    #### List users waiting for approval. ####
    ##########################################
    if ( $msg =~ /^$listapprovals$/ and ircuac->accesscheck($name,$who) >= '500' ) {
	foreach my $line ( ircuac->list_approve() ) {
	    text2irc($name,$line);
	}
    } elsif ( $msg =~ /^$listapprovals$/ and ircuac->accesscheck($name,$who) < '500' ) {
	text2irc($name,"You do not have the required access to view the approval list.");
    }

    #########################################################################################
    #### Approve function, for approval and setting access level of/for registered user. ####
    #########################################################################################
    if ( $msg =~ /^$approve (.+)/ and ircuac->accesscheck($name,$who) >= '500' ) {
	my @userinfo = ( split / /, $msg );
	my $user = $userinfo[1];
	my $accesslevel = $userinfo[2];
	my $send2sub = ircuac->approve($name,$user,$accesslevel);
	
	if ( $send2sub == '1' ) {
	    text2irc($name,"You do not have access to grant this access level, it's higher than your own.");
	}

	if ( $send2sub == '0' ) {
	    text2irc($name,"$user approved with access level $accesslevel.");
	    logcommands("APPROVAL: User: $user where approved with access level: $accesslevel by $name");
	}
	
	if ( $send2sub == '2' ) {
	    text2irc($name,"User is suspended.");
	}
	
	if ( $send2sub == '3' ) {
	    text2irc($name,"$user already approved.");
	}
    }

    ##########################################
    #### List suspended users.		  ####
    ##########################################
    if ( $msg =~ /^$listsuspend$/ and ircuac->accesscheck($name,$who) >= '500' ) {
	foreach my $line ( ircuac->list_suspended() ) {
	    text2irc($name,$line);
	}
    } elsif ( $msg =~ /^$listsuspend$/ and ircuac->accesscheck($name,$who) < '500' ) {
	text2irc($name,"You do not have the required access to view the suspended list.");
    }

    ###########################
    #### Suspend function. ####
    ###########################
    if ( $msg =~ /^$suspend (.+)/ and ircuac->accesscheck($name,$who) >= '500' ) {
	$msg =~ s/$suspend//;
	my @split = ( split / /, $msg);
	my $username = $split[1];
	my $reason = "@split";
	$reason =~ s/$username //;
	chomp($reason);
	my $send2sub = ircuac->suspend($name,$username,$who,"$reason");

	if ( $send2sub == '3' ) {
	    text2irc($name,"User is already suspended.");
	}

	if ( $send2sub == '1') {
	    text2irc($name,"User suspended with reason:$reason");
	    logcommands("SUSPEND: User: $username suspended by $name with reason:$reason");
	    ircuac->commandlog("SUSPEND",$who,$name,$msg,"1");
	}

	if ( $send2sub == '0' ) {
	    text2irc($name,"You can not suspend $username because he/she has a higher access level than you.");
	}
    }

    #############################
    #### Unsuspend function. ####
    #############################
    if ( $msg =~ /^$unsuspend (.+)/ and ircuac->accesscheck($name,$who) >= '500' ) {
	$msg =~ s/$unsuspend//;
	my @split = ( split / /, $msg);
	my $username = $split[1];
	my $reason = "@split";
	chomp($reason);
	my $send2sub = ircuac->unsuspend($name,$username,"$reason");
    
	if ( $send2sub == '0' ) {
	    text2irc($name,"User unsuspended.");
	    logcommands("UNSUSPEND: User: $username unsuspended by $name with reason: $reason");
	}

	if ( $send2sub == '2' ) {
	    text2irc($name,"Can't unsuspend $username, user was suspended at a higher level with access level.");
	}

	if ( $send2sub == '3' ) {
	    text2irc($name,"Can't determin who suspended user, please report to admin.");
	}
    }

    ##########################
    #### Unidentify	  ####
    ##########################
    if ( $msg =~ m/^$unident/ ) {
	my $send2sub = ircuac->unidentify($name,$who);

	if ( $send2sub == 1 ) {
	    text2irc($name,"You unidentified.");
	}
	  
	if ( $send2sub == '0' ) {
	    text2irc($name,"You are not identified with $botnick.");
	}
    }

    #####################
    #### List admins ####
    #####################
    if ( $msg =~ /^$admins$/ ) {
	foreach my $line ( ircuac->listadmins() ) {
	    text2irc($name,$line);
	}
    }
    ######################################################################################################################################################################
    #### Part of ircuac which need some extra attention, we need to do so that if any of these commands are run in channel the user is suspended at the highest level ####
    ######################################################################################################################################################################
    
    #############################################################################################
    #### Register function, will be registered without access and must be approved by admin. ####
    #############################################################################################
    #Added extra security, the bot will not register if command is issued on channel.
    if ( $msg =~ /^$register (.+)/ and $wherefrom eq $botnick ) {
	my @userinfo = ( split / /, $msg );
	my $user = $userinfo[1];
	my $password = $userinfo[2];
	my $send2sub = ircuac->register($user,$password,$name);
	if ( $send2sub == 0 ) {
	    text2irc($name,"Username already taken, try another one.");
	}

	if ( $send2sub == '1' ) {
	    text2irc($name,"You are registered, you must be approved and given access level before you can do anything. If you're in a hurry you should ask an admin. !admins lists you the administrators.")
	}

	if ( $send2sub == '2' ) {
	    text2irc($name,"You need a minimum of $minpasslength characters in your password.");
	}
    } elsif ( $msg =~ /^$register (.+)/ and $wherefrom eq $chan ) {
	text2irc($name,"You need to run this command in private msg with bot, do /msg $botnick $register <username> <password>. PLEASE, choose another password than you just gave the whole channel.");
    }

    ##########################
    #### Change password. ####
    ##########################
    if ( $msg =~ m/^$setpass (.+)/ and $wherefrom eq $botnick ) {
	$msg =~ s/$setpass //;
	my @splitit = ( split / /, $msg );
	chomp($splitit[0]);
	chomp($splitit[1]);
	my $oldpass = $splitit[0];
	my $newpass = $splitit[1];
	my $send2sub = ircuac->changepass($name,$oldpass,$newpass);

	if ( $send2sub == '3' ) {
	    text2irc($name,"You need a minimum of $minpasslength characters in your password.")
	}

	if ( $send2sub == '1' ) {
	    text2irc($name,"Password changed successfully.");
	}
  
	if ( $send2sub == '0' ) {
	    text2irc($name,"Old password not correct.");
	}
    } elsif ( $msg =~ m/^$setpass (.+)/ and $wherefrom eq $chan ) {
	ircuac->suspend("SYSTEM",$name,"SYSTEM","SUSPENDED BY SYSTEM: User tried to change pass in channel.");
	text2irc($name,"You need to run this command in private msg with bot, do /msg $botnick $setpass <oldpass> <newpass>. Your account has been suspended, please contact $botmaster to unlock.");
	
    }

    ##########################
    #### Identify	  ####
    ##########################
    if ( $msg =~ m/^$ident (.+)/ and $wherefrom eq $botnick ) {
	$msg =~ s/$ident //;
	my @userinfo = ( split / /, $msg );
	my $username = $userinfo[0];
	my $password = $userinfo[1];
	my $hostname = $who;
	my $send2sub = ircuac->identify($name,$username,$password,$hostname);
	my $messagecheck = ircuac->message_count($name);
	if ( $send2sub == '1' ) {
	    my $allcount = ircuac->message_count($name);
	    my $newcount = ircuac->new_message_count($name);
	    if ( $messagecheck > '0' ) {
		text2irc($name,"You identified successfully. You have $newcount new message(s) - (There are: $allcount message(s) in your inbox).");
	    } elsif ( $messagecheck <= '0' ) {
		text2irc($name,"You identified successfully.");
	    }
	}
	  
	if ( $send2sub == '0' ) {
	    text2irc($name,"Wrong password, please try again or contact $botmaster");
	}

	if ( $send2sub == '2' ) {
	    text2irc($name,"User does not exist! Sure you typed the correct username? Contact $botmaster or use the !register function.");
	} 
    
	if ( $send2sub == '3' ) {
	    text2irc($name,"NOT IDENTIFIED: You are suspended.");
	} 
    } elsif ( $msg =~ m/^$ident (.+)/ and $wherefrom eq $chan ) {
	ircuac->suspend("SYSTEM",$name,"SYSTEM","SUSPENDED BY SYSTEM: User tried to identify in channel.");
	text2irc($name,"You need to run this command in private msg with bot, do /msg $botnick $ident <nick> <password>. Your account has been suspended, please contact $botmaster to unlock.");
    }

    if ( $msg =~ /^$leavemsg (.+)/ and ircuac->accesscheck($name,$who) >= '50' ) {
	#Remove command from input.
	$msg =~ s/^$leavemsg //;
	#Split message up, so we can extract username.
	my @UserAndBody = ( split / /, $msg );
	#Sends required stuff to leave_message.
	my $send2sub = ircuac->leave_message($name,$who,$UserAndBody[0],@UserAndBody);

	if ( $send2sub == '1' ) {
	    text2irc($name,"Message sent to $UserAndBody[0]");
	}
      
	if ( $send2sub == '2' ) {
	    text2irc($name,"Message was not sent, try logging in or getting the username of the person you want to send to.");
	}
    }

    if ( $msg =~ /^$listmsg/ and ircuac->accesscheck($name,$who) >='50' ) {
	if ( ircuac->message_count($name) > '0' ) {
	foreach my $line ( ircuac->checkmessages($name) ) {
	    text2irc($name,$line);
	}
	} else {
	    text2irc($name,"You have no messages in your inbox.")
	}
    }

    if ( $msg =~ /^$readmsg (.+)/ and ircuac->accesscheck($name,$who) >='50' ) {
	$msg =~ s/^$readmsg //;
	
	foreach my $line ( ircuac->readmessage($name,$msg) ) {
	    text2irc($name,$line);
	}
    }

    if ( $msg =~ /^$delmsg (.+)/ and ircuac->accesscheck($name,$who) >='50' ) {
	$msg =~ s/^$delmsg //;
	my $send2sub = ircuac->delete_message($name,$msg);
    
	if ( $send2sub == '0' ) {
	    text2irc($name,"All messages was deleted successfully.");
	} 
      
	if ( $send2sub == '1' ) {
	    text2irc($name,"Message $msg was deleted successfully.")
	} 

	if ( $send2sub == '3' ) {
	    text2irc($name,"Message does not exist.");
	}
    }
  
    ##############################################################
    #### ircuac (IRC User and Access Control) functions stop  ####
    ##############################################################

    #Search logs - !logsearch 
    if ( $msg =~ /^$logsearch (.+)/ ) {
	$msg =~ s/$logsearch //;
	my @splice = $msg;
	my $direct = "$logdir$chan";
	@splice = splice(@splice,1);
	my @searchpar = ( split / /, $msg );
	my @searchwords = splice(@searchpar,2);

	foreach my $line ( searchlogs->search($direct,$searchpar[0],$searchpar[1],@searchwords) ) {
	    text2irc($name,$line);
	}
    }
    

    if ( $msg =~ m/^$replay (.+)/ ) {
        $msg =~ s/$replay//io;
        text2irc($chan,$msg);
    }

    #Sends message to channel from bot.
    if ( $msg =~ /^$shout (.+)/iog ) {
	$msg =~ s/$shout//io;
	my @message = (split / /, $msg );
	text2irc($chan,"@message ($name)");
    }
    
        #Sends message to channel from bot.
    if ( $msg =~ /^$ashout (.+)/iog and ircuac->accesscheck($name,$who) >= '500' ) {
	$msg =~ s/$ashout//io;
	my @message = (split / /, $msg );
	text2irc($chan,"@message");
    }


    #Set topic in channel.
    if ( $msg =~ m/^$topic (.+)/ and ircuac->accesscheck($name,$who) >= '200' ) {
	$msg =~ s/$topic//io;
	$irc->yield( topic => CHANNEL, "$msg ($name)");
    } elsif ( $msg =~ m/^$topic (.+)/ and ircuac->accesscheck($name,$who) >= '200' ) {
	text2irc($name,"You don't have access to set topic.")
    }

    #HASH Password.
    if ( $msg =~ m/^$md5msg (.+)/ ) {
	$msg =~ s/$md5msg //;
	my $md5 = Digest::MD5->new;
	$md5->add($msg);
	my $md5hash = $md5->hexdigest;
	if ( $wherefrom eq $chan ) {
	    text2irc($chan,$md5hash);
	} elsif ( $wherefrom eq $botnick ) {
	    text2irc($name,$md5hash);
	}
    }

    #Give op to other user.
    if ( $msg =~ m/^$op (.+)/io and ircuac->accesscheck($name,$who) >= '200' ) {
	$msg =~ s/$op //;
	$irc->yield( mode => $chan, '+o', $msg );
	if ( $where ne $chan ) {
	$irc->yield( privmsg => $msg, "You where oped in $chan by $name");
	}
    } elsif ( $msg =~ m/^$op (.+)/io and ircuac->accesscheck($name,$who) < '200' ) {
	text2irc($name,"You do not have access to op other users.")
    }   

    #Give op to yourself.
    if ( $msg =~ m/^$op$/io and ircuac->accesscheck($name,$who) >= '200' ) {
	$irc->yield( mode => $chan, '+o', $name );
    } elsif ( $msg =~ m/^$op$/io and ircuac->accesscheck($name,$who) < '200' ) {
	text2irc($name,"You do not have access to op yourself.");
    }

    #Take op from other user.
    if ( $msg =~ m/^$deop (.+)/io and ircuac->accesscheck($name,$who) >= '200' ) {
	$msg =~ s/$deop //;
	$irc->yield( mode => $chan, '-o', $msg );
    } elsif ( $msg =~ m/^$deop (.+)/io and ircuac->accesscheck($name,$who) < '200' ) {
	text2irc($name,"You do not have access to deop other users.");
    }

    #Deop yourself-
    if ( $msg =~ m/^$deop$/io ) {
	$irc->yield( mode => $chan, '-o', $name );
    }

    #Give voice to other user, !op <adminpass/userpass> <user>
    if ( $msg =~ /^$voice (.+)/io and ircuac->accesscheck($name,$who) >= '100' ) {
	$msg =~ s/$voice //;
	$irc->yield( mode => $chan, '+v', $msg );
	logcommands("VOICE: User: $msg where voiced on $chan by $name");
    } elsif ( $msg =~ /^$voice (.+)/io and ircuac->accesscheck($name,$who) < '100' ) {
	text2irc($name,"You do not have access to voice other users.");
    }

    #Give voice to yourself.
    if ( $msg =~ /^$voice$/io and ircuac->accesscheck($name,$who) >= '100' ) {
	$irc->yield( mode => $chan, '+v', $name );
    } elsif ( $msg =~ /^$voice$/io and ircuac->accesscheck($name,$who) < '100' ) {
	text2irc($name,"You do not have access to voice yourself.");
    }

    #Kill the bot if an admin initiate 
    if ( $msg =~ /^$die/io and ircuac->accesscheck($name,$who) >= '1000' ) {
	logcommands("KILL: User: $name initiated the kill command.");
	$irc->yield( shutdown => "$diemsg");
    } elsif ( $msg =~ /^$die/io and ircuac->accesscheck($name,$who) < '1000' ) {
	text2irc($name,"You do not have access to kill $botnick. Incident logged.");
	logcommands("UNAUTHORIZED KILL ATTEMPT: User: $name tried to initiated the kill command.");
    }

    #Send invite to user.
    if ( $msg =~ /^$invitemsg (.+)/io and ircuac->accesscheck($name,$who) >= '50' ) {
	$msg =~ s/$invitemsg //;
	$irc->call( invite => $msg, CHANNEL );
	$irc->yield( privmsg => $msg, "You where invited to $chan by $name");
	logcommands("INVITE: User: $msg where invited to $chan by $name");
    } elsif ( $msg =~ /^$invitemsg (.+)/io and ircuac->accesscheck($name,$who) < '50' ) {
	text2irc($name,"You do not have access to invite $msg to $chan.");
    }
}

##############################################
#### Subroutine for on_public(irc_public) ####
##############################################

# The bot has received a public message.  Parse it for commands, and
# respond to interesting things.
sub on_public {
    my ( $kernel, $who, $where, $msg ) = @_[ KERNEL, ARG0, ARG1, ARG2 ];
    my $name = ( split /!/, $who )[0];
    my $channel = $where->[0];

    if ( $output == '1' ) {
	#Spam channel messages to shell. 
	my $ts = scalar localtime;
	print " [$ts] <$who:$channel> $msg\n";
    }


}
#### SECTION END ####


##############################################
#### Subroutine for on_invite(irc_invite) ####
##############################################

#What will bot do if invited to channel.
sub on_invite {
    my ( $invitee, $invchannel ) = @_[ ARG0, ARG1 ];
    my $invitor = ( split /!/, $invitee )[0];
    if ( $invchannel eq $chan ) {
	$irc->yield( join => $invchannel );
	
	if ( $useless_greetings == '1' ) {
	    text2irc($chan,"Thanks for the invite, $invitor!");
	}
    }
    #Added to ensure that bot will not join other channels than $chan.
    if ( $invchannel ne $chan ) {
	text2irc($invitor, "I'm not authorized to join $invchannel.");
    }
    
    
}

#### SECTION END ####


##########################################
#### Subroutine for on_mode(irc_mode) ####
##########################################

sub on_mode {
    my ( $nihost, $channel, $mode, $me) = @_[ ARG0, ARG1, ARG2, ARG3 ];
    my $nick = ( split /!/, $nihost )[0];

    if ( $mode =~ m/\+o/g and $me eq $botnick ) {
	#Will set channel mode to $cmode when bot is oped, if mode is not already set.
	$irc->yield( mode => CHANNEL, $cmode );	
	#Says thanks to whoever op the fucking thing, if enabled that is.
	if ( $useless_greetings == '1' ) {
	    text2irc($chan, "Thanks for the doughnut, $nick!");
	}
    }
}

#### SECTION END ####

##########################################
#### Subroutine for on_quit(irc_quit) ####
##########################################

sub on_quit {
    my $who = $_[ARG0];
    #Not needed yet, but added to have it later, if needed.
    
    my $quitmessage = $_[ARG1];
    my $name = ( split /!/, $who )[0];
    
    #Sends userinfo to unidentify subroutine on quit, and if sub return 1 for successfull unident, logg it to commandlog. If 0 should be returned, that would mean that the user was not identified, so no logging will be done.
    my $send2sub = ircuac->unidentify($name,$who);
    if ( $send2sub == '1' ) {
	logcommands("USER UNIDENTIFIED BY SYSTEM BECAUSE OF QUIT: Nick: $name, Host: $who, Reason: $quitmessage");
    }
}

########################################################
#### Subroutine for on_disconnect(irc_disconnected) ####
########################################################
#What will happen when bot recieve a disconnect from server.
sub on_disconnect {
    my ($server) = $_[ARG0];
    logcommands("[IRC] Lost connection to server $server.\n");
}
exit 0;
